iT邦幫忙

第 12 屆 iThome 鐵人賽

DAY 10
0
Software Development

用Canvas打造自己的遊樂場系列 第 10

[Day10]用Canvas打造自己的遊樂場-遊戲版面、剩餘生命

  • 分享至 

  • xImage
  •  

今天首要任務呢是要做一下遊戲範圍的修改,在我遊戲的規劃中,未來會在畫面最上方顯示玩家剩餘性命數量,所以需要在最上方空出一個區域來.
我們用畫線的方式來做區隔就好,首先當然是先做一個畫線的函式,雖然應該只會用上一次,但既然前面球跟矩形都有做函式,當然不能虧待線條啦.

// 畫線
drawLine = (beginX, beginY, endX, endY, color) => {
    canvasContext.strokeStyle = color;
    canvasContext.beginPath();
    canvasContext.moveTo(beginX, beginY);
    canvasContext.lineTo(endX, endY);
    canvasContext.stroke();
}

那我們之後這條線的位置是要按照剩餘壽命的圖案來畫的,再把畫面繪製出來前,就先把函式寫一寫好了.

// 畫生命
drawLife = (lifeX, lifeY, size, color) => {
    canvasContext.fillStyle = color;
    canvasContext.beginPath();
    canvasContext.arc(lifeX + size / 4, lifeY + size / 4, size / 4, Math.PI * 1, Math.PI * 0);
    canvasContext.arc(lifeX + size * 3 / 4, lifeY + size / 4, size / 4, Math.PI * 1, Math.PI * 0);
    canvasContext.moveTo(lifeX + size, lifeY + size / 4);
    canvasContext.lineTo(lifeX + size / 2, lifeY + size);
    canvasContext.lineTo(lifeX, lifeY + size / 4);
    canvasContext.fill();
}

那就開始把這些元件畫出來吧,先來設定生命數量及大小.

// 生命設定
const LIFE_SIZE = 30;
var chance = 3;

先來畫線

// 負責畫畫
draw = () => {
    // background
    drawRectangle(0, 0, canvas.width, canvas.height, 'black');

    // paddle
    drawRectangle(paddle_x, canvas.height - PADDLE_HEIGHT - PADDLE_HIGH,
        PADDLE_WIDTH, PADDLE_HEIGHT, 'white');

    // 畫球
    drawCircle(ball_x, ball_y, ball_r, 'wight');

    // 畫線
    drawLine(0, LIFE_SIZE, canvas.width, LIFE_SIZE, 'white')

}

別忘了修改遊戲頂端的邊界

// 碰觸邊界動作
if (ball_x < (0 + ball_r)) {
    ball_speed_x *= -1;
}
if (ball_x > (canvas.width - ball_r)) {
    ball_speed_x *= -1;
}
if (ball_y < (LIFE_SIZE + ball_r)) {
    ball_speed_y *= -1;
}
if (ball_y > canvas.height) {
    resetBall();
    chance -= 1;

    if (chance < 0) {
        chance = 3;
    }
}

注意在球低於畫面底線時,我們多加了扣生命還有若生命變負值時,會重置生命的設定,先暫時直接調整生命數量,之後再做修改

我們多加一個自動畫出生命的函式

// 畫出生命
showLife = (num) => {
    for (let life_count = 0; life_count < num; life_count++) {
        drawLife(LIFE_SIZE * life_count, 0, LIFE_SIZE, 'red');
    }
}

使用這函式

// 負責畫畫
draw = () => {
    // background
    drawRectangle(0, 0, canvas.width, canvas.height, 'black');

    // paddle
    drawRectangle(paddle_x, canvas.height - PADDLE_HEIGHT - PADDLE_HIGH,
        PADDLE_WIDTH, PADDLE_HEIGHT, 'white');

    // 畫球
    drawCircle(ball_x, ball_y, ball_r, 'wight');

    // 畫線
    drawLine(0, LIFE_SIZE, canvas.width, LIFE_SIZE, 'white')

    // 畫出生命
    showLife(chance);
}

馬上來看看結果吧

應該一切正常吧? 想到明天還要補班,覺得累~~~今天就寫到這吧~~~

最後附上目前的全部程式碼

<!DOCTYPE html>
<html lang="en">

<head>
    <title>First Game</title>
    <meta name="description" content="第一個遊戲">
    <meta content="text/html;charset=utf-8" http-equiv="Content-Type">
    <meta content="utf-8" http-equiv="encoding">
</head>

<body>
    <canvas id="playground" width="800" height="630"></canvas>
    <script>
        var canvas, canvasContext;

        // 球的參數
        var ball_x = 300;
        var ball_y = 300;
        var ball_r = 10;
        var ball_speed = 8;
        var ball_speed_x = 5;
        // 計算Y軸球速
        countBallSpeedY = (speed, speedX) => {
            return (speed ** 2 - speedX ** 2) ** 0.5;
        }
        var ball_speed_y = countBallSpeedY(ball_speed, ball_speed_x);

        // paddle參數
        const PADDLE_WIDTH = 100;
        const PADDLE_HEIGHT = 10;
        const PADDLE_HIGH = 50; // paddle 距離底部高度
        var paddle_x = 400;

        // 生命設定
        const LIFE_SIZE = 30;
        var chance = 3;

        window.onload = () => {
            canvas = document.getElementById('playground');
            canvasContext = canvas.getContext('2d');

            //一秒更新幾次畫面
            var timesPerSec = 30;
            setInterval(drawAll, 1000 / timesPerSec);

            canvas.addEventListener('mousemove', mousePos);
        }

        // 負責更新畫面
        drawAll = () => {
            move();
            draw();
        }

        // 負責畫畫
        draw = () => {
            // background
            drawRectangle(0, 0, canvas.width, canvas.height, 'black');

            // paddle
            drawRectangle(paddle_x, canvas.height - PADDLE_HEIGHT - PADDLE_HIGH,
                PADDLE_WIDTH, PADDLE_HEIGHT, 'white');

            // 畫球
            drawCircle(ball_x, ball_y, ball_r, 'wight');

            // 畫線
            drawLine(0, LIFE_SIZE, canvas.width, LIFE_SIZE, 'white')

            // 畫出生命
            showLife(chance);


        }

        // 負責處理動作
        move = () => {
            ball_x += ball_speed_x;
            ball_y += ball_speed_y;

            // 碰觸邊界動作
            if (ball_x < (0 + ball_r)) {
                ball_speed_x *= -1;
            }
            if (ball_x > (canvas.width - ball_r)) {
                ball_speed_x *= -1;
            }
            if (ball_y < (LIFE_SIZE + ball_r)) {
                ball_speed_y *= -1;
            }
            if (ball_y > canvas.height) {
                resetBall();
                chance -= 1;

                if (chance < 0) {
                    chance = 3;
                }
            }

            // 定義paddle四個角的座標
            var paddleTopEdgeY = canvas.height - PADDLE_HEIGHT - PADDLE_HIGH;
            var paddleBottomEdgeY = paddleTopEdgeY + PADDLE_HEIGHT;
            var paddleLeftEdgeX = paddle_x;
            var paddleRightEdgeX = paddleLeftEdgeX + PADDLE_WIDTH;
            

            // 碰到paddle反彈
            if (ball_y > (paddleTopEdgeY - ball_r) &&
                ball_y < paddleBottomEdgeY &&
                ball_x > paddleLeftEdgeX &&
                ball_x < paddleRightEdgeX) {

                    // 加速
                    ball_speed += 0.5;
                    
                    // paddle中心
                    var centerOfPaddleX = paddle_x + PADDLE_WIDTH / 2;

                    // 計算X軸球速
                    ball_speed_x = ball_speed * ((ball_x - centerOfPaddleX) / (0.51 * PADDLE_WIDTH));

                    // 計算Y軸球速
                    ball_speed_y = -1 * countBallSpeedY(ball_speed, ball_speed_x);
            }
        }

        // 矩形元件
        drawRectangle = (topLeftX, topLeftY, boxWidth, boxHeight, color) => {
            canvasContext.fillStyle = color;
            canvasContext.fillRect(topLeftX, topLeftY, boxWidth, boxHeight);
        }

        // 圓形元件
        drawCircle = (centerX, centerY, r, color) => {
            canvasContext.fillStyle = color;
            canvasContext.beginPath();
            canvasContext.arc(centerX, centerY, r, 0, Math.PI * 2);
            canvasContext.fill();
        }

        // 畫線
        drawLine = (beginX, beginY, endX, endY, color) => {
            canvasContext.strokeStyle = color;
            canvasContext.beginPath();
            canvasContext.moveTo(beginX, beginY);
            canvasContext.lineTo(endX, endY);
            canvasContext.stroke();
        }

        // 畫生命
        drawLife = (lifeX, lifeY, size, color) => {
            canvasContext.fillStyle = color;
            canvasContext.beginPath();
            canvasContext.arc(lifeX + size / 4, lifeY + size / 4, size / 4, Math.PI * 1, Math.PI * 0);
            canvasContext.arc(lifeX + size * 3 / 4, lifeY + size / 4, size / 4, Math.PI * 1, Math.PI * 0);
            canvasContext.moveTo(lifeX + size, lifeY + size / 4);
            canvasContext.lineTo(lifeX + size / 2, lifeY + size);
            canvasContext.lineTo(lifeX, lifeY + size / 4);
            canvasContext.fill();
        }

        // 畫出生命
        showLife = (num) => {
            for (let life_count = 0; life_count < num; life_count++) {
                drawLife(LIFE_SIZE * life_count, 0, LIFE_SIZE, 'red');
            }
        }

        // 游標位置
        mousePos = (event) => {
            var rect = canvas.getBoundingClientRect();
            var root = document.documentElement;

            var mouse_x = event.clientX - rect.left - root.scrollLeft;

            // 設定paddle控制點在中央
            paddle_x = mouse_x - PADDLE_WIDTH / 2;
        }

        // 重置球
        resetBall = () => {
            ball_x = 300;
            ball_y = 300;
            ball_speed = 8;
            ball_speed_x = 5;
            ball_speed_y = countBallSpeedY(ball_speed, ball_speed_x);
        }

        

    </script>
</body>

</html>

上一篇
[Day09]用Canvas打造自己的遊樂場-BB 反彈角度、球速
下一篇
[Day11]用Canvas打造自己的遊樂場-BB 磚塊、陣列、補班日進度少一點
系列文
用Canvas打造自己的遊樂場30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言